<!--  -->
<template>
  <div class="app" id="dbc">
    <i id="bubbleradius"></i>
    <div
      v-for="(c, index) in circles"
      :key="index"
      :class="{ popped: c.popped, 'flex center align bubble': true }"
      :style="style(c)"
      @click.stop="onClick(index)"
      ref="bubble"
    >
      <img
        :src="c.img"
        class="self-img"
        v-show="c.img != ''"
        ondragstart="return"
        loading="lazy"
      />
    </div>
  </div>
</template>
<script>
// const this.globalId = null;
const rotate = (x, y, sin, cos, reverse) => {
  return reverse
    ? {
        x: cos * x + sin * y,
        y: cos * y - sin * x,
      }
    : {
        x: cos * x - sin * y,
        y: cos * y + sin * x,
      };
};

const flatten = (arr) =>
  arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);

import { signatureQuery } from "@/api/apiData";
export default {
  components: {},
  props: ["imgs", "type"],
  data() {
    return {
      max: 20, //默认生成气泡
      circles: [],
      lastExec: null,
      hue: 360,
      lastCollisions: [],
      hiddenProperty: null,
      visibilityChangeEvent: null,
      moving: true,
      globalId: null,
      mark: 1, //0 添加气泡 1重绘气泡
      totalPages: 1,
      page: 0,
      offset: 20,
      img: [],
      count: 0,
      timer: null,
    };
  },
  computed: {},
  watch: {
    imgs() {
      if (this.count == 0) {
        this.init();
        this.count++;
      } else {
        this.appendImg();
      }
    },
  },
  methods: {
    // 获取去签名列表
    getList() {
      const that = this;
      let { totalPages, page, offset, imgs, type } = that;
      let obj = {
        page: page + 1,
        size: offset,
        type: type,
        orderway: "asc",
      };
      if (totalPages > page) {
        signatureQuery(obj).then((res) => {
          if (res.code == 1) {
            if (res.data.total == 0) {
              that.init();
              that.count++;
              return;
            }
            this.img = res.data.list;
            // this.img = imgs.concat(res.data.list);
            this.totalPages = Math.ceil(res.data.total / offset);
            this.page = page + 1;
            let arr = [];
            this.img.forEach((item) => {
              arr.push(item.image);
            });
            this.$emit("Fun", arr);
          }
        });
      } else {
        // 签名列列表全部加载完毕
        this.page = 0;
        this.count = 0;
      }
    },
    appendImg() {
      let index = Math.floor(Math.random() * this.circles.length);
      let length = this.imgs.length - 1;
      let arr = []; //有照片没点破
      let list = []; //有照片被点破
      let pupped = []; //没有照片没点破
      let arry = []; //没有照片被点破
      let selectList = []; //全部被填满照片
      this.circles.forEach((item) => {
        if (item.img != "" && !item.popped) {
          // 气泡有照片没点破
          arr.push(item);
        }
        if (item.img != "") {
          // 全部填满照片
          selectList.push(item);
        }
        if (item.img != "" && item.popped) {
          // 气泡有照片被点破
          list.push(item);
        }
        if (item.img == "" && !item.popped) {
          // 气泡没有照片没有点破
          pupped.push(item);
        }
        if (item.img == "" && item.popped) {
          // 气泡没有照片被点破
          arry.push(item);
        }
      });
      if (this.circles[index].img == "" && !this.circles[index].popped) {
        // 向没有被点破的气泡内添加照片
        this.circles[index].img = this.imgs[length];
      } else {
        if (arry.length + arr.length + list.length == 20) {
          // 空气泡全部被点破
          console.log(222);
          this.circles.forEach((item) => {
            item.popped = false;
          });
        }
        //20个气泡被写满
        if (selectList.length >= 20) {
          this.circles = [];
          this.lastExec = null;
          this.hue = 360;
          this.lastCollisions = [];
          this.hiddenProperty = null;
          this.visibilityChangeEvent = null;
          this.moving = true;
          this.globalId = null;
          this.mark = 1;
          this.init();
          this.getList();
        } else {
          this.appendImg();
        }
      }
    },
    style(c) {
      // 78 156 255  245,196,128,1  59,142,230 ,1
      let color = this.type == 0 ? "245,196,128,1" : "214,85,9,1";
      return `top:${c.y}px;left:${c.x}px;box-shadow:0 0 3rem rgba(${color}) inset`;
    },
    update(tm) {
      if (!this.moving) {
        return;
      }

      if (this.lastExec && this.circles.length) {
        var diff = tm - this.lastExec;
        // var huediff = (this.hue + diff/30) % 360
        var box = this.$el.getBoundingClientRect();
        var radius = this.$el
          .querySelector("#bubbleradius")
          .getBoundingClientRect().width;

        var couples = [];
        this.circles
          .filter((cc) => !cc.popped)
          .forEach((c1) => {
            this.circles
              .filter((cc) => !cc.popped)
              .forEach((c2) => {
                if (c1 !== c2) {
                  couples.push([c1, c2]);
                }
              });
          });

        var collisions = couples.filter((couple) => {
          var dist = Math.sqrt(
            Math.pow(couple[0].y - couple[1].y, 2) +
              Math.pow(couple[0].x - couple[1].x, 2)
          );
          return dist < radius * 2;
        });

        var newcollisions = collisions.filter((couple) => {
          var key = couple[0].key + couple[1].key;
          return this.lastCollisions.indexOf(key) < 0;
        });

        newcollisions.forEach((couple) => {
          var a = couple[0];
          var b = couple[1];

          if (a.collisionFree && b.collisionFree) {
            if (false) {
              a.new_vx =
                (a.vx * (a.mass - b.mass) + 2 * b.mass * b.vx) /
                (a.mass + b.mass);
              a.new_vy =
                (a.vy * (a.mass - b.mass) + 2 * b.mass * b.vy) /
                (a.mass + b.mass);
            } else {
              var dx = b.x - a.x;
              var dy = b.y - a.y;
              var collisionAngle = Math.atan2(dy, dx);
              var sin = Math.sin(collisionAngle);
              var cos = Math.cos(collisionAngle);
              var pos_a = { x: 0, y: 0 };
              var pos_b = rotate(dx, dy, sin, cos, true);
              var vel_a = rotate(a.vx, a.vy, sin, cos, true);
              var vel_b = rotate(b.vx, b.vy, sin, cos, true);
              var vxTotal = vel_a.x - vel_b.x;
              vel_a.x =
                ((a.mass - b.mass) * vel_a.x + 2 * b.mass * vel_b.x) /
                (a.mass + b.mass);
              vel_b.x = vxTotal + vel_a.x;
              pos_a.x += vel_a.x;
              pos_b.x += vel_b.x;

              var pos_a_final = rotate(pos_a.x, pos_a.y, sin, cos, false);
              var vel_a_final = rotate(vel_a.x, vel_a.y, sin, cos, false);
              a.new_x = a.x + pos_a_final.x;
              a.new_y = a.y + pos_a_final.y;
              a.new_vx = vel_a_final.x;
              a.new_vy = vel_a_final.y;

              // each collision shows up in array twice: a->b and b->a
              // var pos_b_final = rotate(pos_b.x, pos_b.y, sin, cos, false)
              // var vel_b_final = rotate(vel_b.x, vel_b.y, sin, cos, false)
              // b.x = a.x + pos_b_final.x
              // b.y = a.y + pos_b_final.y
              // b.new_vx = vel_b_final.x;
              // b.new_vy = vel_b_final.y;
            }
          }
        });

        newcollisions.forEach((couple) => {
          var a = couple[0];
          var b = couple[1];
          if (a.new_vy) {
            a.vx = a.new_vx;
            a.vy = a.new_vy;
            a.x = a.new_x;
            a.y = a.new_y;
            a.hue += 20;
          }
        });

        this.lastCollisions = collisions.map((couple) => {
          return couple[0].key + couple[1].key;
        });

        var collided = [...new Set(flatten(newcollisions))];
        var collidedKeys = collided.map((c) => c.key);

        this.circles.forEach((c) => {
          c.collisionFree = c.collisionFree || collidedKeys.indexOf(c.key) < 0;
          if (c.y < 0) {
            c.vy = Math.abs(c.vy);
          } else if (c.y > box.height) {
            c.vy = -Math.abs(c.vy);
          }
          if (c.x < 0) {
            c.vx = Math.abs(c.vx);
          } else if (c.x > box.width) {
            c.vx = -Math.abs(c.vx);
          }

          c.y += c.vy * diff;
          c.x += c.vx * diff;
        });
      }
      this.lastExec = tm;
      this.globalId = requestAnimationFrame(this.update);
    },
    handleVisibilityChange() {
      if (!document[this.hiddenProperty]) {
        this.globalId = requestAnimationFrame(this.update);
        this.moving = true;
      } else {
        cancelAnimationFrame(this.globalId);
        this.moving = false;
      }
    },
    onClick(index) {
      // 点击泡泡消失
      // let m = {
      //   x: evt.pageX,
      //   y: evt.pageY,
      // };
      // let nearest = null;
      // let nearest_distsq = Infinity;
      // let dx, dy, distsq;
      // var radius = this.$el
      //   .querySelector("#bubbleradius")
      //   .getBoundingClientRect().width;
      // this.circles.forEach((c) => {
      //   dx = m.x - c.x;
      //   dy = m.y - c.y;
      //   distsq = dx * dx + dy * dy;
      //   if (distsq < nearest_distsq && distsq < c.radius * c.radius) {
      //     nearest = c;
      //     nearest_distsq = distsq;
      //   }
      // });

      // if (nearest) {
      //   nearest.popped = true;
      // }
      this.circles[index].popped = true;
      let arr = [];
      this.circles.forEach((item) => {
        if (item.popped) {
          arr.push(item);
        }
      });
      setTimeout(() => {
        this.$refs.bubble[index].style.display = "none";
      }, 100);

      if (arr.length == this.circles.length) {
        this.max = this.circles.length; //重新生成气泡
        this.circles = [];
        this.lastExec = null;
        this.hue = 360;
        this.lastCollisions = [];
        this.hiddenProperty = null;
        this.visibilityChangeEvent = null;
        this.moving = true;
        this.globalId = null;
        this.mark = 1;
        this.init();
      }
    },
    // 初始化
    init() {
      var box = this.$el.getBoundingClientRect();
      var radius = this.$el
        .querySelector("#bubbleradius")
        .getBoundingClientRect().width;
      // var max = (box.width * box.height) / 300 / Math.pow(radius, 1.2);
      // this.getList();

      let circles = [];
      for (var i = 0; i < this.max; i++) {
        circles.push({
          key: Math.random(),
          y: Math.random() * box.height, //
          x: Math.random() * box.width, //
          vx: Math.random() / 5,
          vy: Math.random() / 5,
          hue: Math.random() * 360,
          collisionFree: false,
          mass: 1,
          radius: radius,
          popped: false,
          img:
            this.imgs.length > 0
              ? this.mark == 1
                ? this.imgs[i]
                  ? this.imgs[i]
                  : ""
                : ""
              : "",
          // this.mark == 0 ? "" : this.imgs[i] ? this.imgs[i] : ""
        });
      }
      this.circles = circles;
      this.globalId = requestAnimationFrame(this.update);

      var hidden, visibilityChange;
      if (typeof document.hidden !== "undefined") {
        // Opera 12.10 and Firefox 18 and later support
        hidden = "hidden";
        visibilityChange = "visibilitychange";
      } else if (typeof document.msHidden !== "undefined") {
        hidden = "msHidden";
        visibilityChange = "msvisibilitychange";
      } else if (typeof document.webkitHidden !== "undefined") {
        hidden = "webkitHidden";
        visibilityChange = "webkitvisibilitychange";
      }
      this.hiddenProperty = hidden;
      this.visibilityChangeEvent = visibilityChange;
      document.addEventListener(
        this.visibilityChangeEvent,
        this.handleVisibilityChange,
        false
      );
    },
  },
  created() {},
  mounted() {
    this.getList();
    this.timer = setInterval(() => {
      this.getList();
    }, 60000);
    let btn = document.getElementById("dbc");
    btn.addEventListener("dblclick", () => {
      clearInterval(this.timer);
      this.getList();
      this.timer = setInterval(() => {
        this.getList();
      }, 60000);
    });
  },
  beforeDestroy() {
    document.removeEventListener(
      this.visibilityChangeEvent,
      this.handleVisibilityChange,
      false
    );
  },
};
</script>
<style>
body {
  overflow: hidden;
}
</style>
<style lang='less' scoped>
#bubbleradius {
  width: 4.5rem;
  height: 1px;
  opacity: 0;
  z-index: -1;
  display: block;
}

.app {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 86%;
  height: 85%;
  //   width: 100%;
  // height: 100%;
  color: white;
  z-index: -1;
}

.bubble {
  transform: translate(-50%, -50%);
  border-radius: 9rem;
  height: 9rem;
  width: 9rem;
  position: absolute;
  opacity: 1;
  transition: box-shadow 0.5s ease-in-out, transform 0.07s ease-out,
    opacity 0.04s ease-in;
  /*&:before,
  &:after{
  	content: '';
  	position: absolute;
  	top: 20%;
  	left: 20%;
  	background-color: rgba(cyan, 0.3);
  	width: 55%;
  	height: 55%;
  	border-radius: 50%;
  }
  
  &:after {
  	top: 23%;
  	left: 23%;
  	background-color: $black;
  }*/
}
.self-img {
  width: 8rem;
  height: 8rem;
  border-radius: 50%;
}
.bubble.popped {
  transform: translate(-50%, -50%) scale(2);
  opacity: 0;
}
.bubble:after {
  content: "";
  position: absolute;
  top: 18%;
  left: 18%;
  background-color: rgba(191, 255, 255, 0.6);
  width: 0.6428571429rem;
  height: 1.5rem;
  border-radius: 50%;
  transform: rotate(45deg) scale(0.8);
}
</style>